/*!
 * mincart
 * The Mini Cart is a great way to improve your PayPal shopping cart integration.
 *
 * @version 3.0.6
 * @author Jeff Harrell <https://github.com/jeffharrell/>
 * @url http://www.mincartjs.com/
 * @license MIT <https://github.com/jeffharrell/mincart/raw/master/LICENSE.md>
 */

;(function e(t, n, r) {
    function s(o, u) {
        if (!n[o]) {
            if (!t[o]) {
                var a = typeof require == "function" && require;
                if (!u && a) return a(o, !0);
                if (i) return i(o, !0);
                throw new Error("Cannot find module '" + o + "'")
            }
            var f = n[o] = {exports: {}};
            t[o][0].call(f.exports, function (e) {
                var n = t[o][1][e];
                return s(n ? n : e)
            }, f, f.exports, e, t, n, r)
        }
        return n[o].exports
    }

    var i = typeof require == "function" && require;
    for (var o = 0; o < r.length; o++) s(r[o]);
    return s
})({
    1: [function (require, module, exports) {


//
// The shims in this file are not fully implemented shims for the ES5
// features, but do work for the particular use cases there is in
// the other modules.
//

        var toString = Object.prototype.toString;
        var hasOwnProperty = Object.prototype.hasOwnProperty;

// Array.isArray is supported in IE9
        function isArray(xs) {
            return toString.call(xs) === '[object Array]';
        }

        exports.isArray = typeof Array.isArray === 'function' ? Array.isArray : isArray;

// Array.prototype.indexOf is supported in IE9
        exports.indexOf = function indexOf(xs, x) {
            if (xs.indexOf) return xs.indexOf(x);
            for (var i = 0; i < xs.length; i++) {
                if (x === xs[i]) return i;
            }
            return -1;
        };

// Array.prototype.filter is supported in IE9
        exports.filter = function filter(xs, fn) {
            if (xs.filter) return xs.filter(fn);
            var res = [];
            for (var i = 0; i < xs.length; i++) {
                if (fn(xs[i], i, xs)) res.push(xs[i]);
            }
            return res;
        };

// Array.prototype.forEach is supported in IE9
        exports.forEach = function forEach(xs, fn, self) {
            if (xs.forEach) return xs.forEach(fn, self);
            for (var i = 0; i < xs.length; i++) {
                fn.call(self, xs[i], i, xs);
            }
        };

// Array.prototype.map is supported in IE9
        exports.map = function map(xs, fn) {
            if (xs.map) return xs.map(fn);
            var out = new Array(xs.length);
            for (var i = 0; i < xs.length; i++) {
                out[i] = fn(xs[i], i, xs);
            }
            return out;
        };

// Array.prototype.reduce is supported in IE9
        exports.reduce = function reduce(array, callback, opt_initialValue) {
            if (array.reduce) return array.reduce(callback, opt_initialValue);
            var value, isValueSet = false;

            if (2 < arguments.length) {
                value = opt_initialValue;
                isValueSet = true;
            }
            for (var i = 0, l = array.length; l > i; ++i) {
                if (array.hasOwnProperty(i)) {
                    if (isValueSet) {
                        value = callback(value, array[i], i, array);
                    }
                    else {
                        value = array[i];
                        isValueSet = true;
                    }
                }
            }

            return value;
        };

// String.prototype.substr - negative index don't work in IE8
        if ('ab'.substr(-1) !== 'b') {
            exports.substr = function (str, start, length) {
                // did we get a negative start, calculate how much it is from the beginning of the string
                if (start < 0) start = str.length + start;

                // call the original function
                return str.substr(start, length);
            };
        } else {
            exports.substr = function (str, start, length) {
                return str.substr(start, length);
            };
        }

// String.prototype.trim is supported in IE9
        exports.trim = function (str) {
            if (str.trim) return str.trim();
            return str.replace(/^\s+|\s+$/g, '');
        };

// Function.prototype.bind is supported in IE9
        exports.bind = function () {
            var args = Array.prototype.slice.call(arguments);
            var fn = args.shift();
            if (fn.bind) return fn.bind.apply(fn, args);
            var self = args.shift();
            return function () {
                fn.apply(self, args.concat([Array.prototype.slice.call(arguments)]));
            };
        };

// Object.create is supported in IE9
        function create(prototype, properties) {
            var object;
            if (prototype === null) {
                object = {'__proto__': null};
            }
            else {
                if (typeof prototype !== 'object') {
                    throw new TypeError(
                        'typeof prototype[' + (typeof prototype) + '] != \'object\''
                    );
                }
                var Type = function () {
                };
                Type.prototype = prototype;
                object = new Type();
                object.__proto__ = prototype;
            }
            if (typeof properties !== 'undefined' && Object.defineProperties) {
                Object.defineProperties(object, properties);
            }
            return object;
        }

        exports.create = typeof Object.create === 'function' ? Object.create : create;

// Object.keys and Object.getOwnPropertyNames is supported in IE9 however
// they do show a description and number property on Error objects
        function notObject(object) {
            return ((typeof object != "object" && typeof object != "function") || object === null);
        }

        function keysShim(object) {
            if (notObject(object)) {
                throw new TypeError("Object.keys called on a non-object");
            }

            var result = [];
            for (var name in object) {
                if (hasOwnProperty.call(object, name)) {
                    result.push(name);
                }
            }
            return result;
        }

// getOwnPropertyNames is almost the same as Object.keys one key feature
//  is that it returns hidden properties, since that can't be implemented,
//  this feature gets reduced so it just shows the length property on arrays
        function propertyShim(object) {
            if (notObject(object)) {
                throw new TypeError("Object.getOwnPropertyNames called on a non-object");
            }

            var result = keysShim(object);
            if (exports.isArray(object) && exports.indexOf(object, 'length') === -1) {
                result.push('length');
            }
            return result;
        }

        var keys = typeof Object.keys === 'function' ? Object.keys : keysShim;
        var getOwnPropertyNames = typeof Object.getOwnPropertyNames === 'function' ?
            Object.getOwnPropertyNames : propertyShim;

        if (new Error().hasOwnProperty('description')) {
            var ERROR_PROPERTY_FILTER = function (obj, array) {
                if (toString.call(obj) === '[object Error]') {
                    array = exports.filter(array, function (name) {
                        return name !== 'description' && name !== 'number' && name !== 'message';
                    });
                }
                return array;
            };

            exports.keys = function (object) {
                return ERROR_PROPERTY_FILTER(object, keys(object));
            };
            exports.getOwnPropertyNames = function (object) {
                return ERROR_PROPERTY_FILTER(object, getOwnPropertyNames(object));
            };
        } else {
            exports.keys = keys;
            exports.getOwnPropertyNames = getOwnPropertyNames;
        }

// Object.getOwnPropertyDescriptor - supported in IE8 but only on dom elements
        function valueObject(value, key) {
            return {value: value[key]};
        }

        if (typeof Object.getOwnPropertyDescriptor === 'function') {
            try {
                Object.getOwnPropertyDescriptor({'a': 1}, 'a');
                exports.getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
            } catch (e) {
                // IE8 dom element issue - use a try catch and default to valueObject
                exports.getOwnPropertyDescriptor = function (value, key) {
                    try {
                        return Object.getOwnPropertyDescriptor(value, key);
                    } catch (e) {
                        return valueObject(value, key);
                    }
                };
            }
        } else {
            exports.getOwnPropertyDescriptor = valueObject;
        }

    }, {}], 2: [function (require, module, exports) {

// not implemented
// The reason for having an empty file and not throwing is to allow
// untraditional implementation of this module.

    }, {}], 3: [function (require, module, exports) {
        var process = require("__browserify_process");// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

        var util = require('util');
        var shims = require('_shims');

// resolves . and .. elements in a path array with directory names there
// must be no slashes, empty elements, or device names (c:\) in the array
// (so also no leading and trailing slashes - it does not distinguish
// relative and absolute paths)
        function normalizeArray(parts, allowAboveRoot) {
            // if the path tries to go above the root, `up` ends up > 0
            var up = 0;
            for (var i = parts.length - 1; i >= 0; i--) {
                var last = parts[i];
                if (last === '.') {
                    parts.splice(i, 1);
                } else if (last === '..') {
                    parts.splice(i, 1);
                    up++;
                } else if (up) {
                    parts.splice(i, 1);
                    up--;
                }
            }

            // if the path is allowed to go above the root, restore leading ..s
            if (allowAboveRoot) {
                for (; up--; up) {
                    parts.unshift('..');
                }
            }

            return parts;
        }

// Split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
        var splitPathRe =
            /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
        var splitPath = function (filename) {
            return splitPathRe.exec(filename).slice(1);
        };

// path.resolve([from ...], to)
// posix version
        exports.resolve = function () {
            var resolvedPath = '',
                resolvedAbsolute = false;

            for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
                var path = (i >= 0) ? arguments[i] : process.cwd();

                // Skip empty and invalid entries
                if (!util.isString(path)) {
                    throw new TypeError('Arguments to path.resolve must be strings');
                } else if (!path) {
                    continue;
                }

                resolvedPath = path + '/' + resolvedPath;
                resolvedAbsolute = path.charAt(0) === '/';
            }

            // At this point the path should be resolved to a full absolute path, but
            // handle relative paths to be safe (might happen when process.cwd() fails)

            // Normalize the path
            resolvedPath = normalizeArray(shims.filter(resolvedPath.split('/'), function (p) {
                return !!p;
            }), !resolvedAbsolute).join('/');

            return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
        };

// path.normalize(path)
// posix version
        exports.normalize = function (path) {
            var isAbsolute = exports.isAbsolute(path),
                trailingSlash = shims.substr(path, -1) === '/';

            // Normalize the path
            path = normalizeArray(shims.filter(path.split('/'), function (p) {
                return !!p;
            }), !isAbsolute).join('/');

            if (!path && !isAbsolute) {
                path = '.';
            }
            if (path && trailingSlash) {
                path += '/';
            }

            return (isAbsolute ? '/' : '') + path;
        };

// posix version
        exports.isAbsolute = function (path) {
            return path.charAt(0) === '/';
        };

// posix version
        exports.join = function () {
            var paths = Array.prototype.slice.call(arguments, 0);
            return exports.normalize(shims.filter(paths, function (p, index) {
                if (!util.isString(p)) {
                    throw new TypeError('Arguments to path.join must be strings');
                }
                return p;
            }).join('/'));
        };


// path.relative(from, to)
// posix version
        exports.relative = function (from, to) {
            from = exports.resolve(from).substr(1);
            to = exports.resolve(to).substr(1);

            function trim(arr) {
                var start = 0;
                for (; start < arr.length; start++) {
                    if (arr[start] !== '') break;
                }

                var end = arr.length - 1;
                for (; end >= 0; end--) {
                    if (arr[end] !== '') break;
                }

                if (start > end) return [];
                return arr.slice(start, end - start + 1);
            }

            var fromParts = trim(from.split('/'));
            var toParts = trim(to.split('/'));

            var length = Math.min(fromParts.length, toParts.length);
            var samePartsLength = length;
            for (var i = 0; i < length; i++) {
                if (fromParts[i] !== toParts[i]) {
                    samePartsLength = i;
                    break;
                }
            }

            var outputParts = [];
            for (var i = samePartsLength; i < fromParts.length; i++) {
                outputParts.push('..');
            }

            outputParts = outputParts.concat(toParts.slice(samePartsLength));

            return outputParts.join('/');
        };

        exports.sep = '/';
        exports.delimiter = ':';

        exports.dirname = function (path) {
            var result = splitPath(path),
                root = result[0],
                dir = result[1];

            if (!root && !dir) {
                // No dirname whatsoever
                return '.';
            }

            if (dir) {
                // It has a dirname, strip trailing slash
                dir = dir.substr(0, dir.length - 1);
            }

            return root + dir;
        };


        exports.basename = function (path, ext) {
            var f = splitPath(path)[2];
            // TODO: make this comparison case-insensitive on windows?
            if (ext && f.substr(-1 * ext.length) === ext) {
                f = f.substr(0, f.length - ext.length);
            }
            return f;
        };


        exports.extname = function (path) {
            return splitPath(path)[3];
        };

    }, {"__browserify_process": 5, "_shims": 1, "util": 4}], 4: [function (require, module, exports) {
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

        var shims = require('_shims');

        var formatRegExp = /%[sdj%]/g;
        exports.format = function (f) {
            if (!isString(f)) {
                var objects = [];
                for (var i = 0; i < arguments.length; i++) {
                    objects.push(inspect(arguments[i]));
                }
                return objects.join(' ');
            }

            var i = 1;
            var args = arguments;
            var len = args.length;
            var str = String(f).replace(formatRegExp, function (x) {
                if (x === '%%') return '%';
                if (i >= len) return x;
                switch (x) {
                    case '%s':
                        return String(args[i++]);
                    case '%d':
                        return Number(args[i++]);
                    case '%j':
                        try {
                            return JSON.stringify(args[i++]);
                        } catch (_) {
                            return '[Circular]';
                        }
                    default:
                        return x;
                }
            });
            for (var x = args[i]; i < len; x = args[++i]) {
                if (isNull(x) || !isObject(x)) {
                    str += ' ' + x;
                } else {
                    str += ' ' + inspect(x);
                }
            }
            return str;
        };

        /**
         * Echos the value of a value. Trys to print the value out
         * in the best way possible given the different types.
         *
         * @param {Object} obj The object to print out.
         * @param {Object} opts Optional options object that alters the output.
         */

        /* legacy: obj, showHidden, depth, colors*/
        function inspect(obj, opts) {
            // default options
            var ctx = {
                seen: [],
                stylize: stylizeNoColor
            };
            // legacy...
            if (arguments.length >= 3) ctx.depth = arguments[2];
            if (arguments.length >= 4) ctx.colors = arguments[3];
            if (isBoolean(opts)) {
                // legacy...
                ctx.showHidden = opts;
            } else if (opts) {
                // got an "options" object
                exports._extend(ctx, opts);
            }
            // set default options
            if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
            if (isUndefined(ctx.depth)) ctx.depth = 2;
            if (isUndefined(ctx.colors)) ctx.colors = false;
            if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
            if (ctx.colors) ctx.stylize = stylizeWithColor;
            return formatValue(ctx, obj, ctx.depth);
        }

        exports.inspect = inspect;


// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
        inspect.colors = {
            'bold': [1, 22],
            'italic': [3, 23],
            'underline': [4, 24],
            'inverse': [7, 27],
            'white': [37, 39],
            'grey': [90, 39],
            'black': [30, 39],
            'blue': [34, 39],
            'cyan': [36, 39],
            'green': [32, 39],
            'magenta': [35, 39],
            'red': [31, 39],
            'yellow': [33, 39]
        };

// Don't use 'blue' not visible on cmd.exe
        inspect.styles = {
            'special': 'cyan',
            'number': 'yellow',
            'boolean': 'yellow',
            'undefined': 'grey',
            'null': 'bold',
            'string': 'green',
            'date': 'magenta',
            // "name": intentionally not styling
            'regexp': 'red'
        };


        function stylizeWithColor(str, styleType) {
            var style = inspect.styles[styleType];

            if (style) {
                return '\u001b[' + inspect.colors[style][0] + 'm' + str +
                    '\u001b[' + inspect.colors[style][1] + 'm';
            } else {
                return str;
            }
        }


        function stylizeNoColor(str, styleType) {
            return str;
        }


        function arrayToHash(array) {
            var hash = {};

            shims.forEach(array, function (val, idx) {
                hash[val] = true;
            });

            return hash;
        }


        function formatValue(ctx, value, recurseTimes) {
            // Provide a hook for user-specified inspect functions.
            // Check that value is an object with an inspect function on it
            if (ctx.customInspect &&
                value &&
                isFunction(value.inspect) &&
                // Filter out the util module, it's inspect function is special
                value.inspect !== exports.inspect &&
                // Also filter out any prototype objects using the circular check.
                !(value.constructor && value.constructor.prototype === value)) {
                var ret = value.inspect(recurseTimes);
                if (!isString(ret)) {
                    ret = formatValue(ctx, ret, recurseTimes);
                }
                return ret;
            }

            // Primitive types cannot have properties
            var primitive = formatPrimitive(ctx, value);
            if (primitive) {
                return primitive;
            }

            // Look up the keys of the object.
            var keys = shims.keys(value);
            var visibleKeys = arrayToHash(keys);

            if (ctx.showHidden) {
                keys = shims.getOwnPropertyNames(value);
            }

            // Some type of object without properties can be shortcutted.
            if (keys.length === 0) {
                if (isFunction(value)) {
                    var name = value.name ? ': ' + value.name : '';
                    return ctx.stylize('[Function' + name + ']', 'special');
                }
                if (isRegExp(value)) {
                    return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
                }
                if (isDate(value)) {
                    return ctx.stylize(Date.prototype.toString.call(value), 'date');
                }
                if (isError(value)) {
                    return formatError(value);
                }
            }

            var base = '', array = false, braces = ['{', '}'];

            // Make Array say that they are Array
            if (isArray(value)) {
                array = true;
                braces = ['[', ']'];
            }

            // Make functions say that they are functions
            if (isFunction(value)) {
                var n = value.name ? ': ' + value.name : '';
                base = ' [Function' + n + ']';
            }

            // Make RegExps say that they are RegExps
            if (isRegExp(value)) {
                base = ' ' + RegExp.prototype.toString.call(value);
            }

            // Make dates with properties first say the date
            if (isDate(value)) {
                base = ' ' + Date.prototype.toUTCString.call(value);
            }

            // Make error with message first say the error
            if (isError(value)) {
                base = ' ' + formatError(value);
            }

            if (keys.length === 0 && (!array || value.length == 0)) {
                return braces[0] + base + braces[1];
            }

            if (recurseTimes < 0) {
                if (isRegExp(value)) {
                    return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
                } else {
                    return ctx.stylize('[Object]', 'special');
                }
            }

            ctx.seen.push(value);

            var output;
            if (array) {
                output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
            } else {
                output = keys.map(function (key) {
                    return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
                });
            }

            ctx.seen.pop();

            return reduceToSingleString(output, base, braces);
        }


        function formatPrimitive(ctx, value) {
            if (isUndefined(value))
                return ctx.stylize('undefined', 'undefined');
            if (isString(value)) {
                var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
                    .replace(/'/g, "\\'")
                    .replace(/\\"/g, '"') + '\'';
                return ctx.stylize(simple, 'string');
            }
            if (isNumber(value))
                return ctx.stylize('' + value, 'number');
            if (isBoolean(value))
                return ctx.stylize('' + value, 'boolean');
            // For some reason typeof null is "object", so special case here.
            if (isNull(value))
                return ctx.stylize('null', 'null');
        }


        function formatError(value) {
            return '[' + Error.prototype.toString.call(value) + ']';
        }


        function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
            var output = [];
            for (var i = 0, l = value.length; i < l; ++i) {
                if (hasOwnProperty(value, String(i))) {
                    output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
                        String(i), true));
                } else {
                    output.push('');
                }
            }

            shims.forEach(keys, function (key) {
                if (!key.match(/^\d+$/)) {
                    output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
                        key, true));
                }
            });
            return output;
        }


        function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
            var name, str, desc;
            desc = shims.getOwnPropertyDescriptor(value, key) || {value: value[key]};
            if (desc.get) {
                if (desc.set) {
                    str = ctx.stylize('[Getter/Setter]', 'special');
                } else {
                    str = ctx.stylize('[Getter]', 'special');
                }
            } else {
                if (desc.set) {
                    str = ctx.stylize('[Setter]', 'special');
                }
            }

            if (!hasOwnProperty(visibleKeys, key)) {
                name = '[' + key + ']';
            }
            if (!str) {
                if (shims.indexOf(ctx.seen, desc.value) < 0) {
                    if (isNull(recurseTimes)) {
                        str = formatValue(ctx, desc.value, null);
                    } else {
                        str = formatValue(ctx, desc.value, recurseTimes - 1);
                    }
                    if (str.indexOf('\n') > -1) {
                        if (array) {
                            str = str.split('\n').map(function (line) {
                                return '  ' + line;
                            }).join('\n').substr(2);
                        } else {
                            str = '\n' + str.split('\n').map(function (line) {
                                return '   ' + line;
                            }).join('\n');
                        }
                    }
                } else {
                    str = ctx.stylize('[Circular]', 'special');
                }
            }
            if (isUndefined(name)) {
                if (array && key.match(/^\d+$/)) {
                    return str;
                }
                name = JSON.stringify('' + key);
                if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
                    name = name.substr(1, name.length - 2);
                    name = ctx.stylize(name, 'name');
                } else {
                    name = name.replace(/'/g, "\\'")
                        .replace(/\\"/g, '"')
                        .replace(/(^"|"$)/g, "'");
                    name = ctx.stylize(name, 'string');
                }
            }

            return name + ': ' + str;
        }


        function reduceToSingleString(output, base, braces) {
            var numLinesEst = 0;
            var length = shims.reduce(output, function (prev, cur) {
                numLinesEst++;
                if (cur.indexOf('\n') >= 0) numLinesEst++;
                return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
            }, 0);

            if (length > 60) {
                return braces[0] +
                    (base === '' ? '' : base + '\n ') +
                    ' ' +
                    output.join(',\n  ') +
                    ' ' +
                    braces[1];
            }

            return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
        }


// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
        function isArray(ar) {
            return shims.isArray(ar);
        }

        exports.isArray = isArray;

        function isBoolean(arg) {
            return typeof arg === 'boolean';
        }

        exports.isBoolean = isBoolean;

        function isNull(arg) {
            return arg === null;
        }

        exports.isNull = isNull;

        function isNullOrUndefined(arg) {
            return arg == null;
        }

        exports.isNullOrUndefined = isNullOrUndefined;

        function isNumber(arg) {
            return typeof arg === 'number';
        }

        exports.isNumber = isNumber;

        function isString(arg) {
            return typeof arg === 'string';
        }

        exports.isString = isString;

        function isSymbol(arg) {
            return typeof arg === 'symbol';
        }

        exports.isSymbol = isSymbol;

        function isUndefined(arg) {
            return arg === void 0;
        }

        exports.isUndefined = isUndefined;

        function isRegExp(re) {
            return isObject(re) && objectToString(re) === '[object RegExp]';
        }

        exports.isRegExp = isRegExp;

        function isObject(arg) {
            return typeof arg === 'object' && arg;
        }

        exports.isObject = isObject;

        function isDate(d) {
            return isObject(d) && objectToString(d) === '[object Date]';
        }

        exports.isDate = isDate;

        function isError(e) {
            return isObject(e) && objectToString(e) === '[object Error]';
        }

        exports.isError = isError;

        function isFunction(arg) {
            return typeof arg === 'function';
        }

        exports.isFunction = isFunction;

        function isPrimitive(arg) {
            return arg === null ||
                typeof arg === 'boolean' ||
                typeof arg === 'number' ||
                typeof arg === 'string' ||
                typeof arg === 'symbol' ||  // ES6 symbol
                typeof arg === 'undefined';
        }

        exports.isPrimitive = isPrimitive;

        function isBuffer(arg) {
            return arg && typeof arg === 'object'
                && typeof arg.copy === 'function'
                && typeof arg.fill === 'function'
                && typeof arg.binarySlice === 'function'
                ;
        }

        exports.isBuffer = isBuffer;

        function objectToString(o) {
            return Object.prototype.toString.call(o);
        }


        function pad(n) {
            return n < 10 ? '0' + n.toString(10) : n.toString(10);
        }


        var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
            'Oct', 'Nov', 'Dec'];

// 26 Feb 16:19:34
        function timestamp() {
            var d = new Date();
            var time = [pad(d.getHours()),
                pad(d.getMinutes()),
                pad(d.getSeconds())].join(':');
            return [d.getDate(), months[d.getMonth()], time].join(' ');
        }


// log is just a thin wrapper to console.log that prepends a timestamp
        exports.log = function () {
            console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
        };


        /**
         * Inherit the prototype methods from one constructor into another.
         *
         * The Function.prototype.inherits from lang.js rewritten as a standalone
         * function (not on Function.prototype). NOTE: If this file is to be loaded
         * during bootstrapping this function needs to be rewritten using some native
         * functions as prototype setup using normal JavaScript does not work as
         * expected during bootstrapping (see mirror.js in r114903).
         *
         * @param {function} ctor Constructor function which needs to inherit the
         *     prototype.
         * @param {function} superCtor Constructor function to inherit prototype from.
         */
        exports.inherits = function (ctor, superCtor) {
            ctor.super_ = superCtor;
            ctor.prototype = shims.create(superCtor.prototype, {
                constructor: {
                    value: ctor,
                    enumerable: false,
                    writable: true,
                    configurable: true
                }
            });
        };

        exports._extend = function (origin, add) {
            // Don't do anything if add isn't an object
            if (!add || !isObject(add)) return origin;

            var keys = shims.keys(add);
            var i = keys.length;
            while (i--) {
                origin[keys[i]] = add[keys[i]];
            }
            return origin;
        };

        function hasOwnProperty(obj, prop) {
            return Object.prototype.hasOwnProperty.call(obj, prop);
        }

    }, {"_shims": 1}], 5: [function (require, module, exports) {
// shim for using process in browser

        var process = module.exports = {};

        process.nextTick = (function () {
            var canSetImmediate = typeof window !== 'undefined'
                && window.setImmediate;
            var canPost = typeof window !== 'undefined'
                && window.postMessage && window.addEventListener
            ;

            if (canSetImmediate) {
                return function (f) {
                    return window.setImmediate(f)
                };
            }

            if (canPost) {
                var queue = [];
                window.addEventListener('message', function (ev) {
                    var source = ev.source;
                    if ((source === window || source === null) && ev.data === 'process-tick') {
                        ev.stopPropagation();
                        if (queue.length > 0) {
                            var fn = queue.shift();
                            fn();
                        }
                    }
                }, true);

                return function nextTick(fn) {
                    queue.push(fn);
                    window.postMessage('process-tick', '*');
                };
            }

            return function nextTick(fn) {
                setTimeout(fn, 0);
            };
        })();

        process.title = 'browser';
        process.browser = true;
        process.env = {};
        process.argv = [];

        process.binding = function (name) {
            throw new Error('process.binding is not supported');
        }

// TODO(shtylman)
        process.cwd = function () {
            return '/'
        };
        process.chdir = function (dir) {
            throw new Error('process.chdir is not supported');
        };

    }, {}], 6: [function (require, module, exports) {

        /*!
         * EJS
         * Copyright(c) 2012 TJ Holowaychuk <tj@vision-media.ca>
         * MIT Licensed
         */

        /**
         * Module dependencies.
         */

        var utils = require('./utils')
            , path = require('path')
            , dirname = path.dirname
            , extname = path.extname
            , join = path.join
            , fs = require('fs')
            , read = fs.readFileSync;

        /**
         * Filters.
         *
         * @type Object
         */

        var filters = exports.filters = require('./filters');

        /**
         * Intermediate js cache.
         *
         * @type Object
         */

        var cache = {};

        /**
         * Clear intermediate js cache.
         *
         * @api public
         */

        exports.clearCache = function () {
            cache = {};
        };

        /**
         * Translate filtered code into function calls.
         *
         * @param {String} js
         * @return {String}
         * @api private
         */

        function filtered(js) {
            return js.substr(1).split('|').reduce(function (js, filter) {
                var parts = filter.split(':')
                    , name = parts.shift()
                    , args = parts.join(':') || '';
                if (args) args = ', ' + args;
                return 'filters.' + name + '(' + js + args + ')';
            });
        };

        /**
         * Re-throw the given `err` in context to the
         * `str` of ejs, `filename`, and `lineno`.
         *
         * @param {Error} err
         * @param {String} str
         * @param {String} filename
         * @param {String} lineno
         * @api private
         */

        function rethrow(err, str, filename, lineno) {
            var lines = str.split('\n')
                , start = Math.max(lineno - 3, 0)
                , end = Math.min(lines.length, lineno + 3);

            // Error context
            var context = lines.slice(start, end).map(function (line, i) {
                var curr = i + start + 1;
                return (curr == lineno ? ' >> ' : '    ')
                    + curr
                    + '| '
                    + line;
            }).join('\n');

            // Alter exception message
            err.path = filename;
            err.message = (filename || 'ejs') + ':'
                + lineno + '\n'
                + context + '\n\n'
                + err.message;

            throw err;
        }

        /**
         * Parse the given `str` of ejs, returning the function body.
         *
         * @param {String} str
         * @return {String}
         * @api public
         */

        var parse = exports.parse = function (str, options) {
            var options = options || {}
                , open = options.open || exports.open || '<%'
                , close = options.close || exports.close || '%>'
                , filename = options.filename
                , compileDebug = options.compileDebug !== false
                , buf = "";

            buf += 'var buf = [];';
            if (false !== options._with) buf += '\nwith (locals || {}) { (function(){ ';
            buf += '\n buf.push(\'';

            var lineno = 1;

            var consumeEOL = false;
            for (var i = 0, len = str.length; i < len; ++i) {
                var stri = str[i];
                if (str.slice(i, open.length + i) == open) {
                    i += open.length

                    var prefix, postfix, line = (compileDebug ? '__stack.lineno=' : '') + lineno;
                    switch (str[i]) {
                        case '=':
                            prefix = "', escape((" + line + ', ';
                            postfix = ")), '";
                            ++i;
                            break;
                        case '-':
                            prefix = "', (" + line + ', ';
                            postfix = "), '";
                            ++i;
                            break;
                        default:
                            prefix = "');" + line + ';';
                            postfix = "; buf.push('";
                    }

                    var end = str.indexOf(close, i)
                        , js = str.substring(i, end)
                        , start = i
                        , include = null
                        , n = 0;

                    if ('-' == js[js.length - 1]) {
                        js = js.substring(0, js.length - 2);
                        consumeEOL = true;
                    }

                    if (0 == js.trim().indexOf('include')) {
                        var name = js.trim().slice(7).trim();
                        if (!filename) throw new Error('filename option is required for includes');
                        var path = resolveInclude(name, filename);
                        include = read(path, 'utf8');
                        include = exports.parse(include, {
                            filename: path,
                            _with: false,
                            open: open,
                            close: close,
                            compileDebug: compileDebug
                        });
                        buf += "' + (function(){" + include + "})() + '";
                        js = '';
                    }

                    while (~(n = js.indexOf("\n", n))) n++, lineno++;
                    if (js.substr(0, 1) == ':') js = filtered(js);
                    if (js) {
                        if (js.lastIndexOf('//') > js.lastIndexOf('\n')) js += '\n';
                        buf += prefix;
                        buf += js;
                        buf += postfix;
                    }
                    i += end - start + close.length - 1;

                } else if (stri == "\\") {
                    buf += "\\\\";
                } else if (stri == "'") {
                    buf += "\\'";
                } else if (stri == "\r") {
                    // ignore
                } else if (stri == "\n") {
                    if (consumeEOL) {
                        consumeEOL = false;
                    } else {
                        buf += "\\n";
                        lineno++;
                    }
                } else {
                    buf += stri;
                }
            }

            if (false !== options._with) buf += "'); })();\n} \nreturn buf.join('');";
            else buf += "');\nreturn buf.join('');";
            return buf;
        };

        /**
         * Compile the given `str` of ejs into a `Function`.
         *
         * @param {String} str
         * @param {Object} options
         * @return {Function}
         * @api public
         */

        var compile = exports.compile = function (str, options) {
            options = options || {};
            var escape = options.escape || utils.escape;

            var input = JSON.stringify(str)
                , compileDebug = options.compileDebug !== false
                , client = options.client
                , filename = options.filename
                ? JSON.stringify(options.filename)
                : 'undefined';

            if (compileDebug) {
                // Adds the fancy stack trace meta info
                str = [
                    'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };',
                    rethrow.toString(),
                    'try {',
                    exports.parse(str, options),
                    '} catch (err) {',
                    '  rethrow(err, __stack.input, __stack.filename, __stack.lineno);',
                    '}'
                ].join("\n");
            } else {
                str = exports.parse(str, options);
            }

            if (options.debug) console.log(str);
            if (client) str = 'escape = escape || ' + escape.toString() + ';\n' + str;

            try {
                var fn = new Function('locals, filters, escape, rethrow', str);
            } catch (err) {
                if ('SyntaxError' == err.name) {
                    err.message += options.filename
                        ? ' in ' + filename
                        : ' while compiling ejs';
                }
                throw err;
            }

            if (client) return fn;

            return function (locals) {
                return fn.call(this, locals, filters, escape, rethrow);
            }
        };

        /**
         * Render the given `str` of ejs.
         *
         * Options:
         *
         *   - `locals`          Local variables object
         *   - `cache`           Compiled functions are cached, requires `filename`
         *   - `filename`        Used by `cache` to key caches
         *   - `scope`           Function execution context
         *   - `debug`           Output generated function body
         *   - `open`            Open tag, defaulting to "<%"
         *   - `close`           Closing tag, defaulting to "%>"
         *
         * @param {String} str
         * @param {Object} options
         * @return {String}
         * @api public
         */

        exports.render = function (str, options) {
            var fn
                , options = options || {};

            if (options.cache) {
                if (options.filename) {
                    fn = cache[options.filename] || (cache[options.filename] = compile(str, options));
                } else {
                    throw new Error('"cache" option requires "filename".');
                }
            } else {
                fn = compile(str, options);
            }

            options.__proto__ = options.locals;
            return fn.call(options.scope, options);
        };

        /**
         * Render an EJS file at the given `path` and callback `fn(err, str)`.
         *
         * @param {String} path
         * @param {Object|Function} options or callback
         * @param {Function} fn
         * @api public
         */

        exports.renderFile = function (path, options, fn) {
            var key = path + ':string';

            if ('function' == typeof options) {
                fn = options, options = {};
            }

            options.filename = path;

            var str;
            try {
                str = options.cache
                    ? cache[key] || (cache[key] = read(path, 'utf8'))
                    : read(path, 'utf8');
            } catch (err) {
                fn(err);
                return;
            }
            fn(null, exports.render(str, options));
        };

        /**
         * Resolve include `name` relative to `filename`.
         *
         * @param {String} name
         * @param {String} filename
         * @return {String}
         * @api private
         */

        function resolveInclude(name, filename) {
            var path = join(dirname(filename), name);
            var ext = extname(name);
            if (!ext) path += '.ejs';
            return path;
        }

// express support

        exports.__express = exports.renderFile;

        /**
         * Expose to require().
         */

        if (require.extensions) {
            require.extensions['.ejs'] = function (module, filename) {
                filename = filename || module.filename;
                var options = {filename: filename, client: true}
                    , template = fs.readFileSync(filename).toString()
                    , fn = compile(template, options);
                module._compile('module.exports = ' + fn.toString() + ';', filename);
            };
        } else if (require.registerExtension) {
            require.registerExtension('.ejs', function (src) {
                return compile(src, {});
            });
        }

    }, {"./filters": 7, "./utils": 8, "fs": 2, "path": 3}], 7: [function (require, module, exports) {
        /*!
         * EJS - Filters
         * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
         * MIT Licensed
         */

        /**
         * First element of the target `obj`.
         */

        exports.first = function (obj) {
            return obj[0];
        };

        /**
         * Last element of the target `obj`.
         */

        exports.last = function (obj) {
            return obj[obj.length - 1];
        };

        /**
         * Capitalize the first letter of the target `str`.
         */

        exports.capitalize = function (str) {
            str = String(str);
            return str[0].toUpperCase() + str.substr(1, str.length);
        };

        /**
         * Downcase the target `str`.
         */

        exports.downcase = function (str) {
            return String(str).toLowerCase();
        };

        /**
         * Uppercase the target `str`.
         */

        exports.upcase = function (str) {
            return String(str).toUpperCase();
        };

        /**
         * Sort the target `obj`.
         */

        exports.sort = function (obj) {
            return Object.create(obj).sort();
        };

        /**
         * Sort the target `obj` by the given `prop` ascending.
         */

        exports.sort_by = function (obj, prop) {
            return Object.create(obj).sort(function (a, b) {
                a = a[prop], b = b[prop];
                if (a > b) return 1;
                if (a < b) return -1;
                return 0;
            });
        };

        /**
         * Size or length of the target `obj`.
         */

        exports.size = exports.length = function (obj) {
            return obj.length;
        };

        /**
         * Add `a` and `b`.
         */

        exports.plus = function (a, b) {
            return Number(a) + Number(b);
        };

        /**
         * Subtract `b` from `a`.
         */

        exports.minus = function (a, b) {
            return Number(a) - Number(b);
        };

        /**
         * Multiply `a` by `b`.
         */

        exports.times = function (a, b) {
            return Number(a) * Number(b);
        };

        /**
         * Divide `a` by `b`.
         */

        exports.divided_by = function (a, b) {
            return Number(a) / Number(b);
        };

        /**
         * Join `obj` with the given `str`.
         */

        exports.join = function (obj, str) {
            return obj.join(str || ', ');
        };

        /**
         * Truncate `str` to `len`.
         */

        exports.truncate = function (str, len, append) {
            str = String(str);
            if (str.length > len) {
                str = str.slice(0, len);
                if (append) str += append;
            }
            return str;
        };

        /**
         * Truncate `str` to `n` words.
         */

        exports.truncate_words = function (str, n) {
            var str = String(str)
                , words = str.split(/ +/);
            return words.slice(0, n).join(' ');
        };

        /**
         * Replace `pattern` with `substitution` in `str`.
         */

        exports.replace = function (str, pattern, substitution) {
            return String(str).replace(pattern, substitution || '');
        };

        /**
         * Prepend `val` to `obj`.
         */

        exports.prepend = function (obj, val) {
            return Array.isArray(obj)
                ? [val].concat(obj)
                : val + obj;
        };

        /**
         * Append `val` to `obj`.
         */

        exports.append = function (obj, val) {
            return Array.isArray(obj)
                ? obj.concat(val)
                : obj + val;
        };

        /**
         * Map the given `prop`.
         */

        exports.map = function (arr, prop) {
            return arr.map(function (obj) {
                return obj[prop];
            });
        };

        /**
         * Reverse the given `obj`.
         */

        exports.reverse = function (obj) {
            return Array.isArray(obj)
                ? obj.reverse()
                : String(obj).split('').reverse().join('');
        };

        /**
         * Get `prop` of the given `obj`.
         */

        exports.get = function (obj, prop) {
            return obj[prop];
        };

        /**
         * Packs the given `obj` into json string
         */
        exports.json = function (obj) {
            return JSON.stringify(obj);
        };

    }, {}], 8: [function (require, module, exports) {

        /*!
         * EJS
         * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
         * MIT Licensed
         */

        /**
         * Escape the given string of `html`.
         *
         * @param {String} html
         * @return {String}
         * @api private
         */

        exports.escape = function (html) {
            return String(html)
                .replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/'/g, '&#39;')
                .replace(/"/g, '&quot;');
        };


    }, {}], 9: [function (require, module, exports) {
        'use strict';


        var Product = require('./product'),
            Pubsub = require('./util/pubsub'),
            Storage = require('./util/storage'),
            constants = require('./constants'),
            currency = require('./util/currency'),
            mixin = require('./util/mixin');


        /**
         * Renders the Mini Cart to the page's DOM.
         *
         * @constructor
         * @param {string} name Name of the cart (used as a key for storage)
         * @param {duration} number Time in milliseconds that the cart data should persist
         */
        function Cart(name, duration) {
            var data, items, settings, len, i;

            this._items = [];
            this._settings = {bn: constants.BN};

            Pubsub.call(this);
            Storage.call(this, name, duration);

            if ((data = this.load())) {
                items = data.items;
                settings = data.settings;

                if (settings) {
                    this._settings = settings;
                }

                if (items) {
                    for (i = 0, len = items.length; i < len; i++) {
                        this.add(items[i]);
                    }
                }
            }
        }


        mixin(Cart.prototype, Pubsub.prototype);
        mixin(Cart.prototype, Storage.prototype);


        /**
         * Adds an item to the cart. This fires an "add" event.
         *
         * @param {object} data Item data
         * @return {number} Item location in the cart
         */
        Cart.prototype.add = function add(data) {
            var that = this,
                items = this.items(),
                idx = false,
                isExisting = false,
                product, key, len, i;

            // Prune cart settings data from the product
            for (key in data) {
                if (constants.SETTINGS.test(key)) {
                    this._settings[key] = data[key];
                    delete data[key];
                }
            }

            // Look to see if the same product has already been added
            for (i = 0, len = items.length; i < len; i++) {
                if (items[i].isEqual(data)) {
                    product = items[i];
                    product.set('quantity', product.get('quantity') + (parseInt(data.quantity, 10) || 1));
                    idx = i;
                    isExisting = true;
                    break;
                }
            }

            // If not, then try to add it
            if (!product) {
                product = new Product(data);

                if (product.isValid()) {
                    idx = (this._items.push(product) - 1);

                    product.on('change', function (key, value) {
                        that.save();
                        that.fire('change', idx, key, value);
                    });

                    this.save();
                }
            }

            if (product) {
                this.fire('add', idx, product, isExisting);
            }

            return idx;
        };


        /**
         * Returns the carts current items.
         *
         * @param {number} idx (Optional) Returns only that item.
         * @return {array|object}
         */
        Cart.prototype.items = function get(idx) {
            return (typeof idx === 'number') ? this._items[idx] : this._items;
        };


        /**
         * Returns the carts current settings.
         *
         * @param {string} name (Optional) Returns only that setting.
         * @return {array|string}
         */
        Cart.prototype.settings = function settings(name) {
            return (name) ? this._settings[name] : this._settings;
        };


        /**
         * Returns the cart discount.
         *
         * @param {object} config (Optional) Currency formatting options.
         * @return {number|string}
         */
        Cart.prototype.discount = function discount(config) {
            var result = parseFloat(this.settings('discount_amount_cart')) || 0;

            if (!result) {
                result = (parseFloat(this.settings('discount_rate_cart')) || 0) * this.subtotal() / 100;
            }

            config = config || {};
            config.currency = this.settings('currency_code');

            return currency(result, config);
        };


        /**
         * Returns the cart total without discounts.
         *
         * @param {object} config (Optional) Currency formatting options.
         * @return {number|string}
         */
        Cart.prototype.subtotal = function subtotal(config) {
            var products = this.items(),
                result = 0,
                i, len;

            for (i = 0, len = products.length; i < len; i++) {
                result += products[i].total();
            }

            config = config || {};
            config.currency = this.settings('currency_code');

            return currency(result, config);
        };


        /**
         * Returns the cart total.
         *
         * @param {object} config (Optional) Currency formatting options.
         * @return {number|string}
         */
        Cart.prototype.total = function total(config) {
            var result = 0;

            result += this.subtotal();
            result -= this.discount();

            config = config || {};
            config.currency = this.settings('currency_code');

            return currency(result, config);
        };


        /**
         * Remove an item from the cart. This fires a "remove" event.
         *
         * @param {number} idx Item index to remove.
         * @return {boolean}
         */
        Cart.prototype.remove = function remove(idx) {
            var item = this._items.splice(idx, 1);

            if (this._items.length === 0) {
                this.destroy();
            }

            if (item) {
                this.save();
                this.fire('remove', idx, item[0]);
            }

            return !!item.length;
        };


        /**
         * Saves the cart data.
         */
        Cart.prototype.save = function save() {
            var items = this.items(),
                settings = this.settings(),
                data = [],
                i, len;

            for (i = 0, len = items.length; i < len; i++) {
                data.push(items[i].get());
            }

            Storage.prototype.save.call(this, {
                items: data,
                settings: settings
            });
        };


        /**
         * Proxies the edu_checkout event
         * The assumption is the view triggers this and consumers subscribe to it
         *
         * @param {object} The initiating event
         */
        Cart.prototype.edu_checkout = function edu_checkout(evt) {
            this.fire('edu_checkout', evt);
        };


        /**
         * Destroy the cart data. This fires a "destroy" event.
         */
        Cart.prototype.destroy = function destroy() {
            Storage.prototype.destroy.call(this);

            this._items = [];
            this._settings = {bn: constants.BN};

            this.fire('destroy');
        };


        module.exports = Cart;

    }, {
        "./constants": 11,
        "./product": 13,
        "./util/currency": 15,
        "./util/mixin": 18,
        "./util/pubsub": 19,
        "./util/storage": 20
    }], 10: [function (require, module, exports) {
        'use strict';


        var mixin = require('./util/mixin');


        var defaults = module.exports = {

            name: 'staplesbmincart',

            parent: (typeof document !== 'undefined') ? document.body : null,

            action: 'checkout.html',

            target: '',

            duration: 30,

            template: '<%var items = cart.items();var settings = cart.settings();var hasItems = !!items.length;var priceFormat = { format: true, currency: cart.settings("currency_code") };var totalFormat = { format: true, showCode: true };%><form method="post" class="<% if (!hasItems) { %>sbmincart-empty<% } %>" action="<%= config.action %>" target="<%= config.target %>">    <button type="button" class="sbmincart-closer">&times;</button>    <ul>        <% for (var i= 0, idx = i + 1, len = items.length; i < len; i++, idx++) { %>        <li class="sbmincart-item">            <div class="sbmincart-details-name">                <a class="sbmincart-name" href="<%= items[i].get("href") %>"><%= items[i].get("edu_item") %></a>                <ul class="sbmincart-attributes">                    <% if (items[i].get("item_number")) { %>                    <li>                        <%= items[i].get("item_number") %>                        <input type="hidden" name="item_number_<%= idx %>" value="<%= items[i].get("item_number") %>" />                    </li>                    <% } %>                    <% if (items[i].discount()) { %>                    <li>                        <%= config.strings.discount %> <%= items[i].discount(priceFormat) %>                        <input type="hidden" name="discount_amount_<%= idx %>" value="<%= items[i].discount() %>" />                    </li>                    <% } %>                    <% for (var options = items[i].options(), j = 0, len2 = options.length; j < len2; j++) { %>                        <li>                            <%= options[j].key %>: <%= options[j].value %>                            <input type="hidden" name="on<%= j %>_<%= idx %>" value="<%= options[j].key %>" />                            <input type="hidden" name="os<%= j %>_<%= idx %>" value="<%= options[j].value %>" />                        </li>                    <% } %>                </ul>            </div>            <div class="sbmincart-details-quantity">                <input class="sbmincart-quantity" data-sbmincart-idx="<%= i %>" name="quantity_<%= idx %>" type="text" pattern="[0-9]*" value="<%= items[i].get("quantity") %>" autocomplete="off" />            </div>            <div class="sbmincart-details-remove">                <button type="button" class="sbmincart-remove" data-sbmincart-idx="<%= i %>">&times;</button>            </div>            <div class="sbmincart-details-price">                <span class="sbmincart-price"><%= items[i].total(priceFormat) %></span>            </div>            <input type="hidden" name="edu_item_<%= idx %>" value="<%= items[i].get("edu_item") %>" />            <input type="hidden" name="amount_<%= idx %>" value="<%= items[i].amount() %>" />            <input type="hidden" name="shipping_<%= idx %>" value="<%= items[i].get("shipping") %>" />            <input type="hidden" name="shipping2_<%= idx %>" value="<%= items[i].get("shipping2") %>" />        </li>        <% } %>    </ul>    <div class="sbmincart-footer">        <% if (hasItems) { %>            <div class="sbmincart-subtotal">                <%= config.strings.subtotal %> <%= cart.total(totalFormat) %>            </div>            <button class="sbmincart-submit" type="submit" data-sbmincart-alt="<%= config.strings.buttonAlt %>"><%- config.strings.button %></button>        <% } else { %>            <p class="sbmincart-empty-text"><%= config.strings.empty %></p>        <% } %>    </div>    <input type="hidden" name="cmd" value="_cart" />    <input type="hidden" name="upload" value="1" />    <% for (var key in settings) { %>        <input type="hidden" name="<%= key %>" value="<%= settings[key] %>" />    <% } %></form>',

            styles: '',

            strings: {
                button: 'Check Out',
                subtotal: 'Subtotal:',
                discount: 'Discount:',
                empty: 'Your shopping cart is empty'
            }

        };


        /**
         * Mixes in the user config with the default config.
         *
         * @param {object} userConfig Configuration overrides
         * @return {object}
         */
        module.exports.load = function load(userConfig) {
            return mixin(defaults, userConfig);
        };

    }, {"./util/mixin": 18}], 11: [function (require, module, exports) {
        'use strict';


        module.exports = {

            COMMANDS: {_cart: true, _xclick: true, _donations: true},

            SETTINGS: /^(?:business|currency_code|lc|paymentaction|no_shipping|cn|no_note|invoice|handling_cart|weight_cart|weight_unit|tax_cart|discount_amount_cart|discount_rate_cart|page_style|image_url|cpp_|cs|cbt|return|cancel_return|notify_url|rm|custom|charset)/,

            BN: 'sbmincart_AddToCart_WPS_US',

            KEYUP_TIMEOUT: 500,

            SHOWING_CLASS: 'sbmincart-showing',

            REMOVE_CLASS: 'sbmincart-remove',

            CLOSER_CLASS: 'sbmincart-closer',

            QUANTITY_CLASS: 'sbmincart-quantity',

            ITEM_CLASS: 'sbmincart-item',

            ITEM_CHANGED_CLASS: 'sbmincart-item-changed',

            SUBMIT_CLASS: 'sbmincart-submit',

            DATA_IDX: 'data-sbmincart-idx'

        };

    }, {}], 12: [function (require, module, exports) {
        'use strict';


        var Cart = require('./cart'),
            View = require('./view'),
            config = require('./config'),
            sbmincart = {},
            cartModel,
            confModel,
            viewModel;


        /**
         * Renders the Mini Cart to the page's DOM.
         *
         * @param {object} userConfig Configuration overrides
         */
        sbmincart.render = function (userConfig) {
            confModel = sbmincart.config = config.load(userConfig);
            cartModel = sbmincart.cart = new Cart(confModel.name, confModel.duration);
            viewModel = sbmincart.view = new View({
                config: confModel,
                cart: cartModel
            });

            cartModel.on('add', viewModel.addItem, viewModel);
            cartModel.on('change', viewModel.changeItem, viewModel);
            cartModel.on('remove', viewModel.removeItem, viewModel);
            cartModel.on('destroy', viewModel.hide, viewModel);
        };


        /**
         * Resets the Mini Cart and its view model
         */
        sbmincart.reset = function () {
            cartModel.destroy();

            viewModel.hide();
            viewModel.redraw();
        };


// Export to either node or the brower window
        if (typeof window === 'undefined') {
            module.exports = sbmincart;
        } else {
            if (!window.paypal) {
                window.paypal = {};
            }

            window.edu = sbmincart;
        }

    }, {"./cart": 9, "./config": 10, "./view": 22}], 13: [function (require, module, exports) {
        'use strict';


        var currency = require('./util/currency'),
            Pubsub = require('./util/pubsub'),
            mixin = require('./util/mixin');


        var parser = {
            quantity: function (value) {
                value = parseInt(value, 10);

                if (isNaN(value) || !value) {
                    value = 1;
                }

                return value;
            },
            amount: function (value) {
                return parseFloat(value) || 0;
            },
            href: function (value) {
                if (value) {
                    return value;
                } else {
                    return (typeof window !== 'undefined') ? window.location.href : null;
                }
            }
        };


        /**
         * Creates a new product.
         *
         * @constructor
         * @param {object} data Item data
         */
        function Product(data) {
            data.quantity = parser.quantity(data.quantity);
            data.amount = parser.amount(data.amount);
            data.href = parser.href(data.href);

            this._data = data;
            this._options = null;
            this._discount = null;
            this._amount = null;
            this._total = null;

            Pubsub.call(this);
        }


        mixin(Product.prototype, Pubsub.prototype);


        /**
         * Gets the product data.
         *
         * @param {string} key (Optional) A key to restrict the returned data to.
         * @return {array|string}
         */
        Product.prototype.get = function get(key) {
            return (key) ? this._data[key] : this._data;
        };


        /**
         * Sets a value on the product. This is used rather than manually setting the
         * value so that we can fire a "change" event.
         *
         * @param {string} key
         * @param {string} value
         */
        Product.prototype.set = function set(key, value) {
            var setter = parser[key];

            this._data[key] = setter ? setter(value) : value;
            this._options = null;
            this._discount = null;
            this._amount = null;
            this._total = null;

            this.fire('change', key);
        };


        /**
         * Parse and return the options for this product.
         *
         * @return {object}
         */
        Product.prototype.options = function options() {
            var result, key, value, amount, i, j;

            if (!this._options) {
                result = [];
                i = 0;

                while ((key = this.get('on' + i))) {
                    value = this.get('os' + i);
                    amount = 0;
                    j = 0;

                    while (typeof this.get('option_select' + j) !== 'undefined') {
                        if (this.get('option_select' + j) === value) {
                            amount = parser.amount(this.get('option_amount' + j));
                            break;
                        }

                        j++;
                    }

                    result.push({
                        key: key,
                        value: value,
                        amount: amount
                    });

                    i++;
                }

                this._options = result;
            }

            return this._options;
        };


        /**
         * Parse and return the discount for this product.
         *
         * @param {object} config (Optional) Currency formatting options.
         * @return {number|string}
         */
        Product.prototype.discount = function discount(config) {
            var flat, rate, num, limit, result, amount;

            if (!this._discount) {
                result = 0;
                num = parseInt(this.get('discount_num'), 10) || 0;
                limit = Math.max(num, this.get('quantity') - 1);

                if (this.get('discount_amount') !== undefined) {
                    flat = parser.amount(this.get('discount_amount'));
                    result += flat;
                    result += parser.amount(this.get('discount_amount2') || flat) * limit;
                } else if (this.get('discount_rate') !== undefined) {
                    rate = parser.amount(this.get('discount_rate'));
                    amount = this.amount();

                    result += rate * amount / 100;
                    result += parser.amount(this.get('discount_rate2') || rate) * amount * limit / 100;
                }

                this._discount = result;
            }

            return currency(this._discount, config);
        };


        /**
         * Parse and return the total without discounts for this product.
         *
         * @param {object} config (Optional) Currency formatting options.
         * @return {number|string}
         */
        Product.prototype.amount = function amount(config) {
            var result, options, len, i;

            if (!this._amount) {
                result = this.get('amount');
                options = this.options();

                for (i = 0, len = options.length; i < len; i++) {
                    result += options[i].amount;
                }

                this._amount = result;
            }

            return currency(this._amount, config);
        };


        /**
         * Parse and return the total for this product.
         *
         * @param {object} config (Optional) Currency formatting options.
         * @return {number|string}
         */
        Product.prototype.total = function total(config) {
            var result;

            if (!this._total) {
                result = this.get('quantity') * this.amount();
                result -= this.discount();

                this._total = parser.amount(result);
            }

            return currency(this._total, config);
        };


        /**
         * Determine if this product has the same data as another.
         *
         * @param {object|Product} data Other product.
         * @return {boolean}
         */
        Product.prototype.isEqual = function isEqual(data) {
            var match = false;

            if (data instanceof Product) {
                data = data._data;
            }

            if (this.get('edu_item') === data.edu_item) {
                if (this.get('item_number') === data.item_number) {
                    if (this.get('amount') === parser.amount(data.amount)) {
                        var i = 0;

                        match = true;

                        while (typeof data['os' + i] !== 'undefined') {
                            if (this.get('os' + i) !== data['os' + i]) {
                                match = false;
                                break;
                            }

                            i++;
                        }
                    }
                }
            }

            return match;
        };


        /**
         * Determine if this product is valid.
         *
         * @return {boolean}
         */
        Product.prototype.isValid = function isValid() {
            return (this.get('edu_item') && this.amount() > 0);
        };


        /**
         * Destroys this product. Fires a "destroy" event.
         */
        Product.prototype.destroy = function destroy() {
            this._data = [];
            this.fire('destroy', this);
        };


        module.exports = Product;

    }, {"./util/currency": 15, "./util/mixin": 18, "./util/pubsub": 19}], 14: [function (require, module, exports) {
        /* jshint quotmark:double */


        "use strict";


        module.exports.add = function add(el, str) {
            var re;

            if (!el) {
                return false;
            }

            if (el && el.classList && el.classList.add) {
                el.classList.add(str);
            } else {
                re = new RegExp("\\b" + str + "\\b");

                if (!re.test(el.className)) {
                    el.className += " " + str;
                }
            }
        };


        module.exports.remove = function remove(el, str) {
            var re;

            if (!el) {
                return false;
            }

            if (el.classList && el.classList.add) {
                el.classList.remove(str);
            } else {
                re = new RegExp("\\b" + str + "\\b");

                if (re.test(el.className)) {
                    el.className = el.className.replace(re, "");
                }
            }
        };


        module.exports.inject = function inject(el, str) {
            var style;

            if (!el) {
                return false;
            }

            if (str) {
                style = document.createElement("style");
                style.type = "text/css";

                if (style.styleSheet) {
                    style.styleSheet.cssText = str;
                } else {
                    style.appendChild(document.createTextNode(str));
                }

                el.appendChild(style);
            }
        };

    }, {}], 15: [function (require, module, exports) {
        'use strict';


        var currencies = {
            AED: {before: '\u062c'},
            ANG: {before: '\u0192'},
            ARS: {before: '$', code: true},
            AUD: {before: '$', code: true},
            AWG: {before: '\u0192'},
            BBD: {before: '$', code: true},
            BGN: {before: '\u043b\u0432'},
            BMD: {before: '$', code: true},
            BND: {before: '$', code: true},
            BRL: {before: 'R$'},
            BSD: {before: '$', code: true},
            CAD: {before: '$', code: true},
            CHF: {before: '', code: true},
            CLP: {before: '$', code: true},
            CNY: {before: '\u00A5'},
            COP: {before: '$', code: true},
            CRC: {before: '\u20A1'},
            CZK: {before: 'Kc'},
            DKK: {before: 'kr'},
            DOP: {before: '$', code: true},
            EEK: {before: 'kr'},
            EUR: {before: '\u20AC'},
            GBP: {before: '\u00A3'},
            GTQ: {before: 'Q'},
            HKD: {before: '$', code: true},
            HRK: {before: 'kn'},
            HUF: {before: 'Ft'},
            IDR: {before: 'Rp'},
            ILS: {before: '\u20AA'},
            INR: {before: 'Rs.'},
            ISK: {before: 'kr'},
            JMD: {before: 'J$'},
            JPY: {before: '\u00A5'},
            KRW: {before: '\u20A9'},
            KYD: {before: '$', code: true},
            LTL: {before: 'Lt'},
            LVL: {before: 'Ls'},
            MXN: {before: '$', code: true},
            MYR: {before: 'RM'},
            NOK: {before: 'kr'},
            NZD: {before: '$', code: true},
            PEN: {before: 'S/'},
            PHP: {before: 'Php'},
            PLN: {before: 'z'},
            QAR: {before: '\ufdfc'},
            RON: {before: 'lei'},
            RUB: {before: '\u0440\u0443\u0431'},
            SAR: {before: '\ufdfc'},
            SEK: {before: 'kr'},
            SGD: {before: '$', code: true},
            THB: {before: '\u0E3F'},
            TRY: {before: 'TL'},
            TTD: {before: 'TT$'},
            TWD: {before: 'NT$'},
            UAH: {before: '\u20b4'},
            USD: {before: '$', code: true},
            UYU: {before: '$U'},
            VEF: {before: 'Bs'},
            VND: {before: '\u20ab'},
            XCD: {before: '$', code: true},
            ZAR: {before: 'R'}
        };


        module.exports = function currency(amount, config) {
            var code = config && config.currency || 'USD',
                value = currencies[code],
                before = value.before || '',
                after = value.after || '',
                length = value.length || 2,
                showCode = value.code && config && config.showCode,
                result = amount;

            if (config && config.format) {
                result = before + result.toFixed(length) + after;
            }

            if (showCode) {
                result += ' ' + code;
            }

            return result;
        };

    }, {}], 16: [function (require, module, exports) {
        'use strict';


        module.exports = (function (window, document) {

            /**
             * Events are added here for easy reference
             */
            var cache = [];

            // NOOP for Node
            if (!document) {
                return {
                    add: function () {
                    },
                    remove: function () {
                    }
                };
                // Non-IE events
            } else if (document.addEventListener) {
                return {
                    /**
                     * Add an event to an object and optionally adjust it's scope
                     *
                     * @param obj {HTMLElement} The object to attach the event to
                     * @param type {string} The type of event excluding "on"
                     * @param fn {function} The function
                     * @param scope {object} Object to adjust the scope to (optional)
                     */
                    add: function (obj, type, fn, scope) {
                        scope = scope || obj;

                        var wrappedFn = function (e) {
                            fn.call(scope, e);
                        };

                        obj.addEventListener(type, wrappedFn, false);
                        cache.push([obj, type, fn, wrappedFn]);
                    },


                    /**
                     * Remove an event from an object
                     *
                     * @param obj {HTMLElement} The object to remove the event from
                     * @param type {string} The type of event excluding "on"
                     * @param fn {function} The function
                     */
                    remove: function (obj, type, fn) {
                        var wrappedFn, item, len = cache.length, i;

                        for (i = 0; i < len; i++) {
                            item = cache[i];

                            if (item[0] === obj && item[1] === type && item[2] === fn) {
                                wrappedFn = item[3];

                                if (wrappedFn) {
                                    obj.removeEventListener(type, wrappedFn, false);
                                    cache = cache.slice(i);
                                    return true;
                                }
                            }
                        }
                    }
                };

                // IE events
            } else if (document.attachEvent) {
                return {
                    /**
                     * Add an event to an object and optionally adjust it's scope (IE)
                     *
                     * @param obj {HTMLElement} The object to attach the event to
                     * @param type {string} The type of event excluding "on"
                     * @param fn {function} The function
                     * @param scope {object} Object to adjust the scope to (optional)
                     */
                    add: function (obj, type, fn, scope) {
                        scope = scope || obj;

                        var wrappedFn = function () {
                            var e = window.event;
                            e.target = e.target || e.srcElement;

                            e.preventDefault = function () {
                                e.returnValue = false;
                            };

                            fn.call(scope, e);
                        };

                        obj.attachEvent('on' + type, wrappedFn);
                        cache.push([obj, type, fn, wrappedFn]);
                    },


                    /**
                     * Remove an event from an object (IE)
                     *
                     * @param obj {HTMLElement} The object to remove the event from
                     * @param type {string} The type of event excluding "on"
                     * @param fn {function} The function
                     */
                    remove: function (obj, type, fn) {
                        var wrappedFn, item, len = cache.length, i;

                        for (i = 0; i < len; i++) {
                            item = cache[i];

                            if (item[0] === obj && item[1] === type && item[2] === fn) {
                                wrappedFn = item[3];

                                if (wrappedFn) {
                                    obj.detachEvent('on' + type, wrappedFn);
                                    cache = cache.slice(i);
                                    return true;
                                }
                            }
                        }
                    }
                };
            }

        })(typeof window === 'undefined' ? null : window, typeof document === 'undefined' ? null : document);

    }, {}], 17: [function (require, module, exports) {
        'use strict';


        var forms = module.exports = {

            parse: function parse(form) {
                var raw = form.elements,
                    data = {},
                    pair, value, i, len;

                for (i = 0, len = raw.length; i < len; i++) {
                    pair = raw[i];

                    if ((value = forms.getInputValue(pair))) {
                        data[pair.name] = value;
                    }
                }

                return data;
            },


            getInputValue: function getInputValue(input) {
                var tag = input.tagName.toLowerCase();

                if (tag === 'select') {
                    return input.options[input.selectedIndex].value;
                } else if (tag === 'textarea') {
                    return input.innerText;
                } else {
                    if (input.type === 'radio') {
                        return (input.checked) ? input.value : null;
                    } else if (input.type === 'checkbox') {
                        return (input.checked) ? input.value : null;
                    } else {
                        return input.value;
                    }
                }
            }

        };
    }, {}], 18: [function (require, module, exports) {
        'use strict';


        var mixin = module.exports = function mixin(dest, source) {
            var value;

            for (var key in source) {
                value = source[key];

                if (value && value.constructor === Object) {
                    if (!dest[key]) {
                        dest[key] = value;
                    } else {
                        mixin(dest[key] || {}, value);
                    }
                } else {
                    dest[key] = value;
                }
            }

            return dest;
        };

    }, {}], 19: [function (require, module, exports) {
        'use strict';


        function Pubsub() {
            this._eventCache = {};
        }


        Pubsub.prototype.on = function on(name, fn, scope) {
            var cache = this._eventCache[name];

            if (!cache) {
                cache = this._eventCache[name] = [];
            }

            cache.push([fn, scope]);
        };


        Pubsub.prototype.off = function off(name, fn) {
            var cache = this._eventCache[name],
                i, len;

            if (cache) {
                for (i = 0, len = cache.length; i < len; i++) {
                    if (cache[i] === fn) {
                        cache = cache.splice(i, 1);
                    }
                }
            }
        };


        Pubsub.prototype.fire = function on(name) {
            var cache = this._eventCache[name], i, len, fn, scope;

            if (cache) {
                for (i = 0, len = cache.length; i < len; i++) {
                    fn = cache[i][0];
                    scope = cache[i][1] || this;

                    if (typeof fn === 'function') {
                        fn.apply(scope, Array.prototype.slice.call(arguments, 1));
                    }
                }
            }
        };


        module.exports = Pubsub;

    }, {}], 20: [function (require, module, exports) {
        'use strict';


        var Storage = module.exports = function Storage(name, duration) {
            this._name = name;
            this._duration = duration || 30;
        };


        var proto = Storage.prototype;


        proto.load = function () {
            if (typeof window === 'object' && window.localStorage) {
                var data = window.localStorage.getItem(this._name), today, expires;

                if (data) {
                    data = JSON.parse(decodeURIComponent(data));
                }

                if (data && data.expires) {
                    today = new Date();
                    expires = new Date(data.expires);

                    if (today > expires) {
                        this.destroy();
                        return;
                    }
                }

                return data && data.value;
            }
        };


        proto.save = function (data) {
            if (typeof window === 'object' && window.localStorage) {
                var expires = new Date(), wrapped;

                expires.setTime(expires.getTime() + this._duration * 24 * 60 * 60 * 1000);

                wrapped = {
                    value: data,
                    expires: expires.toGMTString()
                };

                window.localStorage.setItem(this._name, encodeURIComponent(JSON.stringify(wrapped)));
            }
        };


        proto.destroy = function () {
            if (typeof window === 'object' && window.localStorage) {
                window.localStorage.removeItem(this._name);
            }
        };

    }, {}], 21: [function (require, module, exports) {
        'use strict';


        var ejs = require('ejs');


        module.exports = function template(str, data) {
            return ejs.render(str, data);
        };


// Workaround for IE 8's lack of support
        if (!String.prototype.trim) {
            String.prototype.trim = function () {
                return this.replace(/^\s+|\s+$/g, '');
            };
        }

    }, {"ejs": 6}], 22: [function (require, module, exports) {
        'use strict';


        var config = require('./config'),
            events = require('./util/events'),
            template = require('./util/template'),
            forms = require('./util/forms'),
            css = require('./util/css'),
            viewevents = require('./viewevents'),
            constants = require('./constants');


        /**
         * Creates a view model.
         *
         * @constructor
         * @param {object} model
         */
        function View(model) {
            var wrapper;

            this.el = wrapper = document.createElement('div');
            this.model = model;
            this.isShowing = false;

            // HTML
            wrapper.id = config.name;
            config.parent.appendChild(wrapper);

            // CSS
            css.inject(document.getElementsByTagName('head')[0], config.styles);

            // JavaScript
            events.add(document, ('ontouchstart' in window) ? 'touchstart' : 'click', viewevents.click, this);
            events.add(document, 'keyup', viewevents.keyup, this);
            events.add(document, 'readystatechange', viewevents.readystatechange, this);
            events.add(window, 'pageshow', viewevents.pageshow, this);
        }


        /**
         * Tells the view to redraw
         */
        View.prototype.redraw = function redraw() {
            events.remove(this.el.querySelector('form'), 'submit', this.model.cart.edu_checkout, this.model.cart);
            this.el.innerHTML = template(config.template, this.model);
            events.add(this.el.querySelector('form'), 'submit', this.model.cart.edu_checkout, this.model.cart);
        };


        /**
         * Tells the view to show
         */
        View.prototype.show = function show() {
            if (!this.isShowing) {
                css.add(document.body, constants.SHOWING_CLASS);
                this.isShowing = true;
            }
        };


        /**
         * Tells the view to hide
         */
        View.prototype.hide = function hide() {
            if (this.isShowing) {
                css.remove(document.body, constants.SHOWING_CLASS);
                this.isShowing = false;
            }
        };


        /**
         * Toggles the visibility of the view
         */
        View.prototype.toggle = function toggle() {
            this[this.isShowing ? 'hide' : 'show']();
        };


        /**
         * Binds cart submit events to a form.
         *
         * @param {HTMLElement} form
         * @return {boolean}
         */
        View.prototype.bind = function bind(form) {
            var that = this;

            // Don't bind forms without a cmd value
            if (!constants.COMMANDS[form.cmd.value]) {
                return false;
            }

            // Prevent re-binding forms
            if (form.hassbmincart) {
                return false;
            } else {
                form.hassbmincart = true;
            }

            if (form.display) {
                events.add(form, 'submit', function (e) {
                    e.preventDefault();
                    that.show();
                });
            } else {
                events.add(form, 'submit', function (e) {
                    e.preventDefault(e);
                    that.model.cart.add(forms.parse(form));
                });
            }

            return true;
        };


        /**
         * Adds an item to the view.
         *
         * @param {number} idx
         * @param {object} data
         */
        View.prototype.addItem = function addItem(idx, data) {
            this.redraw();
            this.show();

            var els = this.el.querySelectorAll('.' + constants.ITEM_CLASS);
            css.add(els[idx], constants.ITEM_CHANGED_CLASS);
        };


        /**
         * Changes an item in the view.
         *
         * @param {number} idx
         * @param {object} data
         */
        View.prototype.changeItem = function changeItem(idx, data) {
            this.redraw();
            this.show();

            var els = this.el.querySelectorAll('.' + constants.ITEM_CLASS);
            css.add(els[idx], constants.ITEM_CHANGED_CLASS);
        };


        /**
         * Removes an item from the view.
         *
         * @param {number} idx
         */
        View.prototype.removeItem = function removeItem(idx) {
            this.redraw();
        };


        module.exports = View;

    }, {
        "./config": 10,
        "./constants": 11,
        "./util/css": 14,
        "./util/events": 16,
        "./util/forms": 17,
        "./util/template": 21,
        "./viewevents": 23
    }], 23: [function (require, module, exports) {
        'use strict';


        var constants = require('./constants'),
            events = require('./util/events'),
            viewevents;


        module.exports = viewevents = {

            click: function (evt) {
                var target = evt.target,
                    className = target.className;

                if (this.isShowing) {
                    // Cart close button
                    if (className === constants.CLOSER_CLASS) {
                        this.hide();
                        // Product remove button
                    } else if (className === constants.REMOVE_CLASS) {
                        this.model.cart.remove(target.getAttribute(constants.DATA_IDX));
                        // Product quantity input
                    } else if (className === constants.QUANTITY_CLASS) {
                        target[target.setSelectionRange ? 'setSelectionRange' : 'select'](0, 999);
                        // Outside the cart
                    } else if (!(/input|button|select|option/i.test(target.tagName))) {
                        while (target.nodeType === 1) {
                            if (target === this.el) {
                                return;
                            }

                            target = target.parentNode;
                        }

                        this.hide();
                    }
                }
            },


            keyup: function (evt) {
                var that = this,
                    target = evt.target,
                    timer;

                if (target.className === constants.QUANTITY_CLASS) {
                    timer = setTimeout(function () {
                        var idx = parseInt(target.getAttribute(constants.DATA_IDX), 10),
                            cart = that.model.cart,
                            product = cart.items(idx),
                            quantity = parseInt(target.value, 10);

                        if (product) {
                            if (quantity > 0) {
                                product.set('quantity', quantity);
                            } else if (quantity === 0) {
                                cart.remove(idx);
                            }
                        }
                    }, constants.KEYUP_TIMEOUT);
                }
            },


            readystatechange: function () {
                if (/interactive|complete/.test(document.readyState)) {
                    var forms, form, i, len;

                    // Bind to page's forms
                    forms = document.getElementsByTagName('form');

                    for (i = 0, len = forms.length; i < len; i++) {
                        form = forms[i];

                        if (form.cmd && constants.COMMANDS[form.cmd.value]) {
                            this.bind(form);
                        }
                    }

                    // Do the initial render when the buttons are ready
                    this.redraw();

                    // Only run this once
                    events.remove(document, 'readystatechange', viewevents.readystatechange);
                }
            },


            pageshow: function (evt) {
                if (evt.persisted) {
                    this.redraw();
                    this.hide();
                }
            }

        };

    }, {"./constants": 11, "./util/events": 16}]
}, {}, [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23])
;